//
//  ViewController.m
//  Fingerprint
//
//  Created by 马滕亚 on 2020/3/17.
//  Copyright © 2020 M.Y.A. All rights reserved.
//

#import "ViewController.h"
#import <LocalAuthentication/LocalAuthentication.h>
#import "EncryptionTools.h"

@interface ViewController ()<NSURLConnectionDataDelegate>
/** 用来每次接收到的数据，拼接 */
@property (nonatomic, strong) NSMutableData *fileData;
/** 保存目标路径 */
@property (nonatomic, strong) NSString *targetFilePath;
/** 要下载文件的总大小 */
@property (nonatomic, assign) long long expectedContentLength;
/** 当前下载的长度 */
@property (nonatomic, assign) long long currentLength;
/** 输出流 */
@property (nonatomic, strong) NSOutputStream *fileStream;

@property (weak, nonatomic) IBOutlet UIProgressView *progressView;


@property (nonatomic, assign ,getter=isFinished) BOOL finished;


@property (nonatomic, assign) CFRunLoopRef currentRunLoop;


@end

@implementation ViewController



- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
//    [self encryptionsFunc];
}

// 测试NSURLConnection
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    // 将网络操作放在异步线程，异步的运行循环不启动 没有办法监听网络事件！！！
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self loadData];
    });
}

#pragma mark - <NSURLConnectionDataDelegate>
/**
 * 问题：1、没有下载进度，会影响用户体验 2、内存偏高，有一个最大峰值
 * 解决办法：通过代理的方式解决
 * 1、进度跟进
 * 在响应方法中获得总文件大小
 * 每次接收到数据，计算数据的总比例
 * 2、保存文件的思路
 * 保存完成写入磁盘
 *
 * 边下载 边写入
 *  1、NSFileHandle 解决了内存峰值的问题
 *  2、NSOutputStream 输出流
*/

- (void) loadData {
    // 1、url
    NSString *urlStr = @"http://127.0.0.1/01 什么是大数据-科普中国.mp4";
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    // 2、request
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 3、connection
    /**
     * 为了保证连接的正常工作，调用线程runloop 必须运行在默认的运行循环模式下
     */
    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
    // 4、启动连接
    [connection start];
    
    self.finished = NO;
    
    // 5、启动运行循环 runloop
    
//    while (!self.isFinished) {
//        // 启动一次runloop循环 监听事件
//        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
//    }
    
    /** CoreFoundation 框架 CFRunLoop
     CFRunLoopStop(r) 停止指定的RunLoop
     CFRunLoopGetCurrent() 拿到当前的RunLoop
     CFRunLoopRun() 直接启动当前的运行循环
     */
    // 1、拿到当前线程的运行循环
    self.currentRunLoop = CFRunLoopGetCurrent();
    // 2、启动运行循环
    CFRunLoopRun();
}

// 1、接收到服务器的响应 - 状态行&响应头 - 做一些准备工作
// expectedContentLength  需要下载文件的总大小
// suggestedFileName 服务器建议保存的文件名称
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"%@",response);
    
    // 记录文件的总大小
    self.expectedContentLength = response.expectedContentLength;
    self.currentLength = 0;
    // 生产目标文件路径
    self.targetFilePath = [@"/Users/matengya/Desktop/123" stringByAppendingPathComponent:response.suggestedFilename];
    
    [[NSFileManager defaultManager] removeItemAtPath:self.targetFilePath error:nil];
    
    // 创建输出流  以追加的方式打开文件流
    self.fileStream = [[NSOutputStream alloc] initToFileAtPath:self.targetFilePath append:YES];
    // 打开
    [self.fileStream open];
}

//- (NSMutableData *)fileData {
//    if (!_fileData) {
//        _fileData = [NSMutableData new];
//    }
//    return _fileData;
//}

// 2、接收到服务器的数据 - 此代理方法可能会执行很多次 因为拿到多个data
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    self.currentLength += data.length;
    
    // 计算百分比
    float progress = (float) self.currentLength / self.expectedContentLength;
    NSLog(@"%f",progress);
    
    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressView.progress = progress;
    });
    
//    // 拼接数据
//    [self.fileData appendData:data];
    
//    // 边下载 边写入
//    [self writeToFileWithData:data];
    
    // 将文件追加到输出流里面
    // (nonnull const uint8_t *)
    [self.fileStream write:data.bytes maxLength:data.length];
}


// 边下载 边写入 NSFileHandle
- (void)writeToFileWithData:(NSData *)data {
    /**
     * NSFileManager：主要功能，创建目录，检查目录是否存在，遍历目录，删除文件，针对文件操作 Finder
     *
     * NSFileHandle：文件“句柄”（文件指针），Handle 意味着是对前面的单词的“File”操作，主要功能，就是对同一个文件进行二进制的读和写
     */
    
    // 注意：如果文件不存在 ，fp 在实例化的结果是空
    NSFileHandle *filePath = [NSFileHandle fileHandleForWritingAtPath:self.targetFilePath];
    // 判断文件是否存在 - 如果文件不存在 直接将数据写入磁盘
    if (filePath == nil) {
        [data writeToFile:self.targetFilePath atomically:YES];
    } else {
        // 1、将文件指针移动到文件的末尾
        [filePath seekToEndOfFile];
        // 2、写入文件
        [filePath writeData:data];
        // 3、关闭文件，在C语言的开发中，凡是涉及到文件读、写 打开和关闭的操作
        [filePath closeFile];
    }
}

// 3、所有的数据加载完毕 - 所有数据都传输完毕 只是一个最后的通知
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"完毕");
//    // 把数据写入磁盘
//    [self.fileData writeToFile:self.targetFilePath atomically:YES];
//    // 最后需要释放掉 fileData
//    self.fileData = nil;
    
    // 关闭文件流
    [self.fileStream close];
    
//    self.finished = YES;
    
    
    // 停止下载线程的运行循环
    CFRunLoopStop(self.currentRunLoop);
}

// 4、下载失败或者错误
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    
}




#pragma mark - 测试
// 异步下载
/**
 * 1、没有下载进度
 * 2、保存文件内存不下
 */
- (void)asynLoadData {
    // 1、url
    NSString *urlStr = @"http://127.0.0.1/01 什么是大数据-科普中国.mp4";
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    // 2、request
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        // 将数据写入磁盘
        [data writeToFile:@"/Users/matengya/Desktop/123.mp4" atomically:YES];
    }];
}


// 高级密码学
- (void)encryptionsFunc {
    // AES - ECB 加密
    NSString *key = @"hk";
    // 加密
    NSLog(@"加密：%@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil]);
    NSString *new = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];
    // 解密
    NSLog(@"解密：%@",[[EncryptionTools sharedEncryptionTools] decryptString:new keyString:key iv:nil]);
    
    // AES - CBC 加密
    uint8_t iv[8] = {1,2,3,4,5,6,7,8};
    NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
    NSLog(@"CBC加密：%@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:ivData]);
    NSString *new1 = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:ivData];
    NSLog(@"CBC解密：%@",[[EncryptionTools sharedEncryptionTools] decryptString:new1 keyString:key iv:ivData]);
    
    // DES
    [EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmDES;
    NSString *new2 = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];
    NSLog(@"DES 加密：%@",new2);
    NSLog(@"DES 解密：%@",[[EncryptionTools sharedEncryptionTools] decryptString:new2 keyString:key iv:nil]);
    
}




// 指纹识别
- (void)laContext {
    LAContext *context = [[LAContext alloc] init];
    
    // 判断设备是否支持指纹识别
    if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:NULL]) {
        // 输入指纹
        [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"指纹支付" reply:^(BOOL success, NSError * _Nullable error) {
            NSLog(@"%d %@",success, error);
        }];
    } else {
        NSLog(@"不支持");
    }
}


@end
